package org.iabako.client.ui.form.user.userconfiguration;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTMLPanel;
import org.iabako.client.config.page.PageConfigEnum;
import org.iabako.client.tools.IabakoAsyncCallback;
import org.iabako.client.ui.form.AbstractForm;
import org.iabako.client.ui.layout.field.*;
import org.iabako.client.ui.layout.template.MenuMyAccount;
import org.iabako.client.ui.layout.widget.validation.ValidationMessage;
import org.iabako.client.user.AuthenticateUserProvider;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.user.User;
import org.iabako.shared.exception.IabakoUniqueConstraintException;
import org.iabako.shared.iservice.user.UserServiceAsync;
import org.iabako.shared.tools.GenericTools;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by jose on 24/09/14.
 */
public class MyUserForm extends AbstractForm {

    interface MyUiBinder extends UiBinder<HTMLPanel, MyUserForm> {
    }

    protected MyUiBinder binderForm = GWT.create(MyUiBinder.class);

    protected final UserServiceAsync userServiceAsync = UserServiceAsync.Util.getInstance();

    @UiField
    InputText firstName;
    @UiField
    InputText lastName;
    @UiField
    InputTextEmail email;
    @UiField
    LabelText newPasswordLink;
    @UiField
    InputTextPassword oldPassword;
    @UiField
    protected InputTextPassword newPassword;
    @UiField
    protected InputTextPassword newPasswordAgain;
    @UiField
    HTMLPanel newPasswordPanel;
    @UiField
    protected LabelText title;
    @UiField
    protected Button saveAction;
    @UiField
    HTMLPanel limitedVisibilityPanel;
    @UiField
    HTMLPanel limitedVisibilityOtherOptions;
    @UiField
    protected CheckboxBoolean limitedVisibility;
    @UiField
    protected CheckboxBoolean financialAccess;
    @UiField
    protected CheckboxBoolean stockAccess;
    @UiField
    protected CheckboxBoolean deletePermission;
    @UiField
    LabelText limitedVisibilityNote;
    @UiField
    protected HTMLPanel passwordPanel;

    private User user;
    protected boolean createForm;

    @UiConstructor
    public MyUserForm(boolean simplePopup) {
        if (simplePopup) {
            this.simplePopup = true;
            setForm(binderForm, PageConfigEnum.UserForm, null);
            messages.setSimplePopup(true);
            title.setLabel("user_create_form_title");
            newPassword.setLimitedInputTitle(false);
            newPasswordAgain.setLimitedInputTitle(false);
            limitedVisibilityPanel.setVisible(true);

            limitedVisibility.getCheckbox().addValueChangeHandler(new ValueChangeHandler<Boolean>() {
                public void onValueChange(ValueChangeEvent<Boolean> booleanValueChangeEvent) {
                    limitedVisibilityOtherOptions.setVisible(limitedVisibility.getValue());
                }
            });

            saveAction.setVisible(true);
        } else {
            initWidget(binderForm.createAndBindUi(this));
            newPasswordLink.setVisible(true);

            userServiceAsync.getById(AuthenticateUserProvider.getUser().getId(), new IabakoAsyncCallback<AbstractEntity>() {
                public void onSuccess(AbstractEntity entity) {
                    setUser((User) entity);
                    super.onSuccess(entity);
                }
            });
        }
        setHandlers();
    }

    protected void setUser(User user) {
        if (user != null) {
            this.user = user;
            firstName.setValue(user.getFirstName());
            lastName.setValue(user.getLastName());
            email.setValue(user.getEmail());
            newPasswordLink.setVisible(true);
            limitedVisibility.setValue(user.isLimitedVisibility());
            financialAccess.setValue(user.isLimitedVisibility() && !user.isNoFinancialAccess());
            stockAccess.setValue(user.isLimitedVisibility() && !user.isNoStockAccess());
            deletePermission.setValue(user.isLimitedVisibility() && !user.isNoDeletePermission());

            //Only visible if limitedVisibility activated (because modification mode is disable)
            if (this.simplePopup) {
                limitedVisibilityPanel.setVisible(user.isLimitedVisibility());
                limitedVisibilityOtherOptions.setVisible(user.isLimitedVisibility());
                limitedVisibilityNote.setVisible(user.isLimitedVisibility());
            }
        }
    }

    private void setHandlers() {
        newPasswordLink.getLabel().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (newPasswordPanel.isVisible()) {
                    newPasswordPanel.setVisible(false);
                    oldPassword.setValue(null);
                    newPassword.setValue(null);
                    newPasswordAgain.setValue(null);
                    newPasswordLink.setLabel("new_password_link");
                } else {
                    newPasswordPanel.setVisible(true);
                    newPasswordLink.setLabel("no_new_password_link");
                }
            }
        });

        oldPassword.getInputField().addBlurHandler(new BlurHandler() {
            public void onBlur(BlurEvent event) {
                if (!GenericTools.isEmpty(oldPassword.getValue()) && !isOldPasswordValid()) {
                    oldPassword.addErrorMessage(oldPassword, true, "old_password_do_not_match");
                } else {
                    newPasswordAgain.clearErrorMessage(oldPassword, "old_password_do_not_match");
                }
            }
        });

        newPassword.getInputField().addBlurHandler(new BlurHandler() {
            public void onBlur(BlurEvent event) {
                if (newPasswordAgain.getValue() != null && !isNewPasswordAgainValid()) {
                    newPasswordAgain.addErrorMessage(newPasswordAgain, true, "passwords_not_equal");
                } else {
                    newPasswordAgain.clearErrorMessage(newPasswordAgain, "passwords_not_equal");
                }
            }
        });

        newPasswordAgain.getInputField().addBlurHandler(new BlurHandler() {
            public void onBlur(BlurEvent event) {
                if (newPasswordAgain.getValue() != null && !isNewPasswordAgainValid()) {
                    newPasswordAgain.addErrorMessage(newPasswordAgain, true, "passwords_not_equal");
                } else {
                    newPasswordAgain.clearErrorMessage(newPasswordAgain, "passwords_not_equal");
                }
            }
        });

        saveAction.getButton().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent clickEvent) {
                saveAction();
            }
        });
    }

    private void saveAction() {
        final MyUserForm thisForm = this;
        if (validate()) {

            //This set user attribute
            getEntity();

            if (createForm) {
                user.setActive(true);
            }
            userServiceAsync.save(user, getNewSaveUserHandler(thisForm));
        }
    }

    public boolean isOldPasswordValid() {
        return user.getPassword().equals(GenericTools.getMd5(oldPassword.getValue()));
    }

    public boolean isNewPasswordAgainValid() {
        return newPassword.getValue() != null
                && newPassword.getValue().equals(newPasswordAgain.getValue());
    }

    @Override
    protected List<IField> getMandatoryFields() {
        List<IField> mandatoryFields = new ArrayList<IField>();
        mandatoryFields.addAll(Arrays.asList((IField) firstName, lastName, email));

        if (newPasswordPanel.isVisible()) {
            mandatoryFields.addAll(Arrays.asList((IField) oldPassword, newPassword, newPasswordAgain));
        }

        return mandatoryFields;
    }

    @Override
    protected AbstractEntity getEntity() {
        if (user == null) {
            user = new User();
        }

        user.setFirstName(firstName.getValue());
        user.setLastName(lastName.getValue());
        user.setEmail(email.getValue());
        user.setLimitedVisibility(limitedVisibility.getValue());
        user.setNoFinancialAccess(limitedVisibility.getValue() && !financialAccess.getValue());
        user.setNoStockAccess(limitedVisibility.getValue() && !stockAccess.getValue());
        user.setNoDeletePermission(limitedVisibility.getValue() && !deletePermission.getValue());

        boolean sameTwoNewPassword = newPassword.getValue() != null
                && newPassword.getValue().equals(newPasswordAgain.getValue());

        if (createForm && sameTwoNewPassword
                || (newPasswordPanel.isVisible()
                && user.getPassword().equals(GenericTools.getMd5(oldPassword.getValue()))
                && sameTwoNewPassword)) {
            user.setPassword(GenericTools.getMd5(newPassword.getValue()));
        }
        return user;
    }

    private class SaveUserHandler extends IabakoAsyncCallback<User> {

        AbstractForm form;

        private SaveUserHandler(AbstractForm form) {
            this.form = form;
        }

        @Override
        public void onFailure(Throwable caught) {
            super.onFailure(caught);

            if (caught instanceof IabakoUniqueConstraintException) {
                //unique constraint user error doesn't close popup background
                errorDialogBox.setAvoidClosePopupCall(false);
                errorDialogBox.setCloseOnlySimplePopup(true);
            }
        }

        public void onSuccess(User result) {
            form.popup.handleClickClose();
            if (parentForm != null) {
                ((UsersForm) parentForm).refreshUsers();
            }
            ValidationMessage validationMessageInPageContent = ValidationMessage.getFromRootPage();
            validationMessageInPageContent.showSuccessMessage("validation_users_configuration_form_success");

            if (result.getId().equals(AuthenticateUserProvider.getUser().getId())) {
                AuthenticateUserProvider.setUser(result);
                MenuMyAccount menuMyAccount = (MenuMyAccount) GenericTools.getWidget(DOM.getElementById("menu_my_account_"));
                menuMyAccount.refreshUserInformation();
            }
            super.onSuccess(result);
        }

    }

    public AsyncCallback<User> getNewSaveUserHandler(AbstractForm myUserForm) {
        return new SaveUserHandler(myUserForm);
    }

    @Override
    public boolean validate() {
        if (!uiValidation()) {
            return false;
        }

        if (newPasswordPanel.isVisible() && !isNewPasswordAgainValid()) {
            newPasswordAgain.addErrorMessage(newPasswordAgain, true, "passwords_not_equal");
            return false;
        }
        return true;
    }
}
